#include "ThrumasterRocker.h"
#include <QDebug>
#include "Utils.h"

ThrumasterRocker::ThrumasterRocker(QObject *parent)
    : QObject{parent}
{
    // 初始化 HIDAPI 库
    if (hid_init()) {
        qCritical() << "Failed to initialize HIDAPI library.";
    }

    // 枚举所有连接的 HID 设备
    struct hid_device_info *devs, *cur_dev;
    devs = hid_enumerate(0x0, 0x0);
    cur_dev = devs;

    // 遍历所有HID设备，找到生产商名为"Thustmaster"的设备，为摇杆
    while (cur_dev) {
        qDebug() << QString::fromWCharArray(cur_dev->manufacturer_string);
        if (QString::fromWCharArray(cur_dev->manufacturer_string).contains("Thustmaster")) {
            device = hid_open_path(cur_dev->path);
            break;
        }
        cur_dev = cur_dev->next;
    }

    hid_free_enumeration(devs);
}

ThrumasterRocker::~ThrumasterRocker()
{
    if (device) {
        hid_close(device);
    }
    hid_exit();
}

void ThrumasterRocker::readRawData() {
    // 读取摇杆数据
    if (device) {
        unsigned char buf[65];
        memset(buf, 0, sizeof(buf));

        // 读取一次数据
        int res = hid_read(device, buf, sizeof(buf));
        if (res > 0) {
            parseButtons(buf, res);
            parseTriggers(buf, res);
            parseAxis4(buf, res);
            parseAxis5(buf, res);
            parseAxis81(buf, res);
            parseAxis82(buf, res);
            parseRocker(buf,res);
        }
    } else {
        qCritical() << "No Thustmaster rocker found.";
    }
}

/*
 * data :   字节数组
 * n    :   字节个数
*/
void ThrumasterRocker::parseButtons(unsigned char data[], int n)
{
    if(n > 2) {
        quint8 secondByte = data[1];
        if((secondByte & 0x04) >> 2)
            setButton1(ThrumasterRocker::Button_PUSHED);
        else
            setButton1(ThrumasterRocker::Button_RELEASE);

        if((secondByte & 0x02) >> 1)
            setButton2(ThrumasterRocker::Button_PUSHED);
        else
            setButton2(ThrumasterRocker::Button_RELEASE);

        if((secondByte & 0x10) >> 4)
            setButton3(ThrumasterRocker::Button_PUSHED);
        else
            setButton3(ThrumasterRocker::Button_RELEASE);
    }
}

void ThrumasterRocker::parseTriggers(unsigned char data[], int n)
{
    if(n > 2) {
        quint8 secondByte = data[1];
        if((secondByte & 0x08) >> 3)
            setTrigger1(ThrumasterRocker::Trigger_PUSHED);
        else
            setTrigger1(ThrumasterRocker::Trigger_RELEASE);

        if(secondByte & 0x01)
            setTrigger2(ThrumasterRocker::Trigger_PUSHED);
        else
            setTrigger2(ThrumasterRocker::Trigger_RELEASE);
    }
}

void ThrumasterRocker::parseAxis4(unsigned char data[], int n)
{
    if(n > 4) {
        quint8 fourthByte = data[3];
        switch (fourthByte) {
        case 0x00:
            setAxis4(ThrumasterRocker::Axis_UP);
            break;
        case 0x20:
            setAxis4(ThrumasterRocker::Axis_RIGHT);
            break;
        case 0x40:
            setAxis4(ThrumasterRocker::Axis_DOWN);
            break;
        case 0x60:
            setAxis4(ThrumasterRocker::Axis_LEFT);
            break;
        case 0xf0:
            setAxis4(ThrumasterRocker::Axis_RELEASE);
            break;
        }
    }
}

void ThrumasterRocker::parseAxis5(unsigned char data[], int n)
{
    if(n > 4) {
        quint8 thirdByte = data[2], fourthByte = data[3];

        int tag = 0;    // 标志位，如果解析axis5完成后，tag还是0，则将其设置成release
        if((thirdByte & 0x40) >> 6) {
            setAxis5(ThrumasterRocker::Axis_UP);
            tag = 1;
        }

        if((thirdByte & 0x80) >> 7) {
            setAxis5(ThrumasterRocker::Axis_RIGHT);
            tag = 1;
        }

        switch (fourthByte) {
        case 0xf1:
            setAxis5(ThrumasterRocker::Axis_DOWN);
            tag = 1;
            break;
        case 0xf2:
            setAxis5(ThrumasterRocker::Axis_LEFT);
            tag = 1;
            break;
        case 0xf4:
            setAxis5(ThrumasterRocker::Axis_PRESSED);
            tag = 1;
            break;
        }

        if(!tag)
            setAxis5(ThrumasterRocker::Axis_RELEASE);
    }
}

void ThrumasterRocker::parseAxis81(unsigned char data[], int n) {
    if(n > 3) {
        quint8 thirdByte = data[2];

        switch(thirdByte) {
        case 0x04:
            setAxis81(ThrumasterRocker::Axis_UP);
            break;
        case 0x10:
            setAxis81(ThrumasterRocker::Axis_DOWN);
            break;
        case 0x20:
            setAxis81(ThrumasterRocker::Axis_LEFT);
            break;
        case 0x08:
            setAxis81(ThrumasterRocker::Axis_RIGHT);
            break;
        case 0x24:
            setAxis81(ThrumasterRocker::Axis_LEFT_UP);
            break;
        case 0x30:
            setAxis81(ThrumasterRocker::Axis_LEFT_DOWN);
            break;
        case 0x0c:
            setAxis81(ThrumasterRocker::Axis_RIGHT_UP);
            break;
        case 0x18:
            setAxis81(ThrumasterRocker::Axis_RIGHT_DOWN);
            break;
        default:
            setAxis81(ThrumasterRocker::Axis_RELEASE);
        }
    }
}

void ThrumasterRocker::parseAxis82(unsigned char data[], int n)
{
    if(n > 3) {
        quint8 secondByte = data[1], thirdByte = data[2];

        int tag = 0;

        switch(secondByte) {
        case 0x40:
            setAxis82(ThrumasterRocker::Axis_UP);
            tag = 1;
            break;
        case 0x80:
            setAxis82(ThrumasterRocker::Axis_RIGHT);
            tag = 1;
            break;
        case 0xc0:
            setAxis82(ThrumasterRocker::Axis_RIGHT_UP);
            tag = 1;
            break;
        }

        switch(thirdByte) {
        case 0x01:
            setAxis82(ThrumasterRocker::Axis_DOWN);
            tag = 1;
            break;
        case 0x02:
            setAxis82(ThrumasterRocker::Axis_LEFT);
            tag = 1;
            break;
        case 0x03:
            setAxis82(ThrumasterRocker::Axis_LEFT_DOWN);
            tag = 1;
            break;
        }

        if(secondByte == 0x40 && thirdByte == 0x02) {
            setAxis82(ThrumasterRocker::Axis_LEFT_UP);
            tag = 1;
        }

        if(secondByte == 0x80 && thirdByte == 0x01) {
            setAxis82(ThrumasterRocker::Axis_RIGHT_DOWN);
            tag = 1;
        }

        if(!tag)
            setAxis82(ThrumasterRocker::Axis_RELEASE);
    }
}

void ThrumasterRocker::parseRocker(unsigned char data[], int n)
{
    // 横向
    if(n > 6) {
        quint8 sixthByte = data[5];
        setRockerX(Utils::normalization(sixthByte, 0xff, 0x00, 0.02));
    }

    // 纵向
    if(n > 8) {
        quint8 eighthByte = data[7];
        setRockerY(Utils::normalization(eighthByte, 0xff, 0x00, 0.02));
    }
}

ThrumasterRocker::ButtonState ThrumasterRocker::button1() const
{
    return m_button1;
}

void ThrumasterRocker::setButton1(ButtonState newButton1)
{
    if (m_button1 == newButton1)
        return;
    m_button1 = newButton1;
    emit button1Changed();
}

ThrumasterRocker::ButtonState ThrumasterRocker::button2() const
{
    return m_button2;
}

void ThrumasterRocker::setButton2(ButtonState newButton2)
{
    if (m_button2 == newButton2)
        return;
    m_button2 = newButton2;
    emit button2Changed();
}

ThrumasterRocker::ButtonState ThrumasterRocker::button3() const
{
    return m_button3;
}

void ThrumasterRocker::setButton3(ButtonState newButton3)
{
    if (m_button3 == newButton3)
        return;
    m_button3 = newButton3;
    emit button3Changed();
}

ThrumasterRocker::TriggerState ThrumasterRocker::trigger1() const
{
    return m_trigger1;
}

void ThrumasterRocker::setTrigger1(TriggerState newTrigger1)
{
    if (m_trigger1 == newTrigger1)
        return;
    m_trigger1 = newTrigger1;
    emit trigger1Changed();
}

ThrumasterRocker::TriggerState ThrumasterRocker::trigger2() const
{
    return m_trigger2;
}

void ThrumasterRocker::setTrigger2(TriggerState newTrigger2)
{
    if (m_trigger2 == newTrigger2)
        return;
    m_trigger2 = newTrigger2;
    emit trigger2Changed();
}

ThrumasterRocker::AxisState ThrumasterRocker::axis4() const
{
    return m_axis4;
}

void ThrumasterRocker::setAxis4(AxisState newAxis4)
{
    if (m_axis4 == newAxis4)
        return;
    m_axis4 = newAxis4;
    emit axis4Changed();
}

ThrumasterRocker::AxisState ThrumasterRocker::axis5() const
{
    return m_axis5;
}

void ThrumasterRocker::setAxis5(AxisState newAxis5)
{
    if (m_axis5 == newAxis5)
        return;
    m_axis5 = newAxis5;
    emit axis5Changed();
}

ThrumasterRocker::AxisState ThrumasterRocker::axis81() const
{
    return m_axis81;
}

void ThrumasterRocker::setAxis81(AxisState newAxis81)
{
    if (m_axis81 == newAxis81)
        return;
    m_axis81 = newAxis81;
    emit axis81Changed();
}

ThrumasterRocker::AxisState ThrumasterRocker::axis82() const
{
    return m_axis82;
}

void ThrumasterRocker::setAxis82(AxisState newAxis82)
{
    if (m_axis82 == newAxis82)
        return;
    m_axis82 = newAxis82;
    emit axis82Changed();
}

double ThrumasterRocker::rockerX() const
{
    return m_rockerX;
}

void ThrumasterRocker::setRockerX(double newRockerX)
{
    if (qFuzzyCompare(m_rockerX, newRockerX))
        return;
    m_rockerX = newRockerX;
    emit rockerXChanged();
}

double ThrumasterRocker::rockerY() const
{
    return m_rockerY;
}

void ThrumasterRocker::setRockerY(double newRockerY)
{
    if (qFuzzyCompare(m_rockerY, newRockerY))
        return;
    m_rockerY = newRockerY;
    emit rockerYChanged();
}
